package org.biogroovy.search;

import groovy.util.logging.Slf4j

import java.text.ParseException
import java.text.SimpleDateFormat

import org.biogroovy.models.IModel

/**
 * This class represents a search.
 *
 */
@Slf4j
public class Search implements Serializable, IModel {

	/** The serial UID */
	private static final long serialVersionUID = 3992764557837220620L;

	/** The name of the search. */
	private String name;

	/** The time the search was last executed. */
	private Date lastExecuted = new Date();

	/** A flag indicating that the search has results. */
	private boolean hasResults;

	private SearchParamSet searchParams = new SearchParamSet();

	/** A list of search results. */
	private List<SearchResult> results = null;

	/**
	 * The name of the search engine. Used to retrieve the appropriate search
	 * engine from a registered map of search engines.
	 */
	private String searchEngineName;

	/** The formatter used to parse and format search dates. */
	private SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

	/** The set of tags associated with the search. */
	private Set<String> tagSet = new HashSet<>();

	/**
	 * Constructor.
	 */
	public Search(){
	}


	/**
	 * Constructor.
	 * 
	 * @param searchEngineName
	 *            the name of the search engine
	 * @param term
	 *            the search term(s)
	 * @param name
	 *            the name of the search
	 */
	public Search(String searchEngineName, String name) {
		this.searchEngineName = searchEngineName;
		this.name = name;
	}


	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}


	public Date getLastExecuted() {
		return lastExecuted;
	}

	public void setLastExecuted(Date lastExecuted) {
		this.lastExecuted = lastExecuted;
	}

	public void setLastExecutedString(String lastExec){
		log.info("lastExec: " + lastExec);
		try{
			this.lastExecuted = dateFormatter.parse(lastExec);
		}catch (ParseException ex){
			log.info(ex.getMessage(), ex);
		}
	}

	public String getLastExecutedAsString(){
		return dateFormatter.format(lastExecuted);
	}

	public boolean isHasResults() {

		return (results == null)?false:!results.isEmpty();
	}


	public String getSearchEngineName() {
		return searchEngineName;
	}

	public void setSearchEngineName(String searchEngineName) {
		this.searchEngineName = searchEngineName;
	}

	public void setSearchParamValues(Map<String, String> paramMap){
		searchParams.setParameterValues(paramMap);
	}

	public SearchParamSet getSearchParams(){
		return searchParams;
	}

	public void setSearchParams(SearchParamSet params){
		searchParams = params;
	}


	/**
	 * Gets the search results.
	 * 
	 * @return the list of search results.
	 */
	public List<SearchResult> getResults() {
		return results;
	}

	/**
	 * Sets the search results.
	 * 
	 * @param results the list of results
	 */
	public void setResults(List<SearchResult> results) {
		this.results = results;
	}

	/**
	 * Gets the number of search results.
	 * 
	 * @return the number of search results
	 */
	public Integer getResultCount(){
		Integer resultCount = 0;
		if (results != null){
			resultCount = results.size();
		}
		return resultCount;
	}

	/**
	 * Sets the value of a parameter.
	 * @param name
	 * @param value
	 */
	public void setParameterValue(String name, String value){
		SearchParam param = searchParams.get(name);
		if (param != null){
			param.setValue(value);
		}else {
			throw new RuntimeException("No parameter with the name: " + name);
		}
	}

	/**
	 * Gets the tags associated with the search.
	 * @return a set of tags for the search.
	 */
	public Set<String> getTagSet(){
		return tagSet;
	}

	/**
	 * Sets the tags associated with the search.
	 * @param tags the new tags.
	 */
	public void setTagSet(Set<String> tags){
		this.tagSet = tags;
	}

	/**
	 * Adds a tag to the search
	 * @param tag the tag to be added.
	 */
	public void addTag(String tag){
		tagSet.add(tag);
	}




	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + (hasResults ? 1231 : 1237);
		result = prime * result
		+ ((lastExecuted == null) ? 0 : lastExecuted.hashCode());
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		result = prime * result + ((results == null) ? 0 : results.hashCode());
		result = prime * result
		+ ((searchEngineName == null) ? 0 : searchEngineName.hashCode());
		result = prime * result
		+ ((searchParams == null) ? 0 : searchParams.hashCode());
		return result;
	}


	@Override
	public boolean equals(Object obj) {
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Search other = (Search) obj;
		if (hasResults != other.hasResults)
			return false;

		if (lastExecuted == null) {
			if (other.lastExecuted != null)
				return false;
		} else if (!lastExecuted.equals(other.lastExecuted))
			return false;


		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;


		if (results == null) {
			if (other.results != null)
				return false;
		} else if (!results.equals(other.results))
			return false;


		if (searchEngineName == null) {
			if (other.searchEngineName != null)
				return false;
		} else if (!searchEngineName.equals(other.searchEngineName))
			return false;


		if (searchParams == null) {
			if (other.searchParams != null)
				return false;
		} else if (!searchParams.equals(other.searchParams))
			return false;

		return true;
	}


	@Override
	public String toString() {
		return "Search [name=" + name +  ", lastExecuted="
		+ lastExecuted + ", hasResults=" + hasResults + ", searchEngineName="
		+ searchEngineName + "]";
	}


	@Override
	public String getModelId() {
		return name;
	}
}
